home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / DT_INSV.PY < prev    next >
Encoding:
Python Source  |  2000-05-12  |  15.2 KB  |  445 lines

  1. ##############################################################################
  2. # Zope Public License (ZPL) Version 1.0
  3. # -------------------------------------
  4. # Copyright (c) Digital Creations.  All rights reserved.
  5. # This license has been certified as Open Source(tm).
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are
  8. # met:
  9. # 1. Redistributions in source code must retain the above copyright
  10. #    notice, this list of conditions, and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. #    notice, this list of conditions, and the following disclaimer in
  13. #    the documentation and/or other materials provided with the
  14. #    distribution.
  15. # 3. Digital Creations requests that attribution be given to Zope
  16. #    in any manner possible. Zope includes a "Powered by Zope"
  17. #    button that is installed by default. While it is not a license
  18. #    violation to remove this button, it is requested that the
  19. #    attribution remain. A significant investment has been put
  20. #    into Zope, and this effort will continue if the Zope community
  21. #    continues to grow. This is one way to assure that growth.
  22. # 4. All advertising materials and documentation mentioning
  23. #    features derived from or use of this software must display
  24. #    the following acknowledgement:
  25. #      "This product includes software developed by Digital Creations
  26. #      for use in the Z Object Publishing Environment
  27. #      (http://www.zope.org/)."
  28. #    In the event that the product being advertised includes an
  29. #    intact Zope distribution (with copyright and license included)
  30. #    then this clause is waived.
  31. # 5. Names associated with Zope or Digital Creations must not be used to
  32. #    endorse or promote products derived from this software without
  33. #    prior written permission from Digital Creations.
  34. # 6. Modified redistributions of any form whatsoever must retain
  35. #    the following acknowledgment:
  36. #      "This product includes software developed by Digital Creations
  37. #      for use in the Z Object Publishing Environment
  38. #      (http://www.zope.org/)."
  39. #    Intact (re-)distributions of any official Zope release do not
  40. #    require an external acknowledgement.
  41. # 7. Modifications are encouraged but must be packaged separately as
  42. #    patches to official Zope releases.  Distributions that do not
  43. #    clearly separate the patches from the original work must be clearly
  44. #    labeled as unofficial distributions.  Modifications which do not
  45. #    carry the name Zope may be packaged in any form, as long as they
  46. #    conform to all of the clauses above.
  47. # Disclaimer
  48. #   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
  49. #   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  50. #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  51. #   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
  52. #   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  53. #   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  54. #   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  55. #   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  56. #   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  57. #   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  58. #   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  59. #   SUCH DAMAGE.
  60. # This software consists of contributions made by Digital Creations and
  61. # many individuals on behalf of Digital Creations.  Specific
  62. # attributions are listed in the accompanying credits file.
  63. ##############################################################################
  64. __doc__='''Sequence variables support
  65.  
  66.  
  67. $Id: DT_InSV.py,v 1.17 2000/05/12 18:36:39 tseaver Exp $'''
  68. __version__='$Revision: 1.17 $'[11:-2]
  69.  
  70. from string import lower, rfind, split, join
  71. from math import sqrt
  72. TupleType=type(())
  73. try:
  74.     import Missing
  75.     mv=Missing.Value
  76. except: mv=None
  77.  
  78.  
  79. class sequence_variables:
  80.  
  81.     def __init__(self,items=None,query_string='',start_name_re=None):
  82.         
  83.         self.items=items
  84.         self.query_string=query_string
  85.         self.start_name_re=start_name_re
  86.  
  87.         self.data=data={
  88.             'previous-sequence': 0,
  89.             'next-sequence': 0,
  90.             'sequence-start': 1,
  91.             'sequence-end': 0,
  92.             }
  93.  
  94.  
  95.     def number(self,index): return index+1
  96.     def even(self,index): return index%2 == 0
  97.     def odd(self,index): return index%2
  98.     def letter(self,index): return chr(ord('a')+index)
  99.     def Letter(self,index): return chr(ord('A')+index)
  100.     def key(self,index):    return self.items[index][0]
  101.     def item(self,index, tt=type(())):
  102.         i=self.items[index]
  103.         if type(i) is tt and len(i)==2: return i[1]
  104.         return i
  105.  
  106.     def roman(self,index): return lower(self.Roman(index))
  107.  
  108.     def Roman(self,num):
  109.         # Force number to be an integer value
  110.         num = int(num)+1
  111.  
  112.         # Initialize roman as an empty string
  113.         roman = ''
  114.  
  115.         while num >= 1000:
  116.                 num = num - 1000
  117.                 roman = '%sM' % roman
  118.  
  119.         while num >= 500:
  120.                 num = num - 500
  121.                 roman = '%sD' % roman
  122.  
  123.         while num >= 100:
  124.                 num = num - 100
  125.                 roman = '%sC' % roman
  126.  
  127.         while num >= 50:
  128.                 num = num - 50
  129.                 roman = '%sL' % roman
  130.  
  131.         while num >= 10:
  132.                 num = num - 10
  133.                 roman = '%sX' % roman                 
  134.  
  135.         while num >= 5:
  136.                 num = num - 5
  137.                 roman = '%sV' % roman
  138.  
  139.         while num < 5 and num >= 1:
  140.                 num = num - 1
  141.                 roman = '%sI' % roman
  142.  
  143.         # Replaces special cases in Roman Numerals
  144.         
  145.         roman = sub('DCCCC', 'CM', roman)
  146.         roman = sub('CCCC', 'CD', roman)
  147.         roman = sub('LXXXX', 'XC', roman)
  148.         roman = sub('XXXX', 'XL', roman)
  149.         roman = sub('VIIII', 'IX', roman)
  150.         roman = sub('IIII', 'IV', roman)
  151.  
  152.         return roman
  153.  
  154.  
  155.     def value(self,index,name):
  156.         data=self.data
  157.         item=self.items[index]
  158.         if type(item)==TupleType and len(item)==2:
  159.             item=item[1]
  160.         if data['mapping']: return item[name]
  161.         return getattr(item,name)
  162.  
  163.     def first(self,name,key=''):
  164.         data=self.data
  165.         if data['sequence-start']: return 1
  166.         index=data['sequence-index']
  167.         return self.value(index,name) != self.value(index-1,name)
  168.  
  169.     def last(self,name,key=''):
  170.         data=self.data
  171.         if data['sequence-end']: return 1
  172.         index=data['sequence-index']
  173.         return self.value(index,name) != self.value(index+1,name)
  174.  
  175.     def length(self, ignored):
  176.         l=self.data['sequence-length']=len(self.items)
  177.         return l
  178.  
  179.     def query(self, *ignored):
  180.         if self.start_name_re is None: raise KeyError, 'sequence-query'
  181.         query_string=self.query_string
  182.         while query_string and query_string[:1] in '?&':
  183.             query_string=query_string[1:]
  184.         while query_string[-1:] == '&':
  185.             query_string=query_string[:-1]
  186.         if query_string:
  187.             query_string='&%s&' % query_string                  
  188.             re=self.start_name_re
  189.             l=re.search_group(query_string, (0,))
  190.             if l:
  191.                 v=l[1]
  192.                 l=l[0]
  193.                 query_string=(query_string[:l]+
  194.                               query_string[l+len(v)-1:])
  195.             query_string='?'+query_string[1:]
  196.         else: query_string='?'
  197.         self.data['sequence-query']=query_string
  198.         return query_string
  199.         
  200.  
  201.     statistic_names=(
  202.         'total', 'count', 'min', 'max', 'median', 'mean',
  203.         'variance', 'variance-n','standard-deviation', 'standard-deviation-n',
  204.         )
  205.  
  206.     def statistics(self,name,key):
  207.         items=self.items
  208.         data=self.data
  209.         mapping=data['mapping']
  210.         count=sum=sumsq=0
  211.         min=max=None
  212.         scount=smin=smax=None
  213.         values=[]
  214.         svalues=[]
  215.         for item in items:
  216.             try:
  217.                 if mapping: item=item[name]
  218.                 else: item=getattr(item,name)
  219.                 try:
  220.                     if item is mv:
  221.                         item = None
  222.                     if type(item)==type(1):
  223.                         s=item*long(item)
  224.                     else:
  225.                         s=item*item
  226.                     sum=sum+item
  227.                     sumsq=sumsq+s
  228.                     values.append(item)
  229.                     if min is None:
  230.                         min=max=item
  231.                     else:
  232.                         if item < min: min=item
  233.                         if item > max: max=item
  234.                 except:
  235.                     if item is not None and item is not mv:
  236.                         if smin is None: smin=smax=item
  237.                         else:
  238.                             if item < smin: smin=item
  239.                             if item > smax: smax=item
  240.                         svalues.append(item)
  241.             except: pass
  242.  
  243.         # Initialize all stats to empty strings:
  244.         for stat in self.statistic_names: data['%s-%s' % (stat,name)]=''
  245.  
  246.         count=len(values)
  247.         try: # Numeric statistics
  248.             n=float(count)
  249.             mean=sum/n
  250.             sumsq=sumsq/n - mean*mean
  251.             data['mean-%s' % name]=mean
  252.             data['total-%s' % name]=sum
  253.             data['variance-n-%s' % name]=sumsq
  254.             data['standard-deviation-n-%s' % name]=sqrt(sumsq)
  255.             if count > 1:
  256.                 sumsq=sumsq*n/(n-1)
  257.                 data['variance-%s' % name]=sumsq
  258.                 data['standard-deviation-%s' % name]=sqrt(sumsq)            
  259.             else:
  260.                 data['variance-%s' % name]=''
  261.                 data['standard-deviation-%s' % name]=''
  262.         except:
  263.             if min is None: min,max,values=smin,smax,svalues
  264.             else:
  265.                 if smin < min: min=smin
  266.                 if smax > max: max=smax
  267.                 values=values+svalues
  268.             count=len(values)
  269.  
  270.         data['count-%s' % name]=count
  271.         # data['_values']=values
  272.         if min is not None:
  273.             data['min-%s' % name]=min
  274.             data['max-%s' % name]=max
  275.             values.sort()
  276.             if count==1:
  277.                 data['median-%s' % name]=min
  278.             else:
  279.                 n=count+1
  280.                 if n/2*2==n: data['median-%s' % name]=values[n/2-1]
  281.                 else:
  282.                     n=n/2
  283.                     try: data['median-%s' % name]=(values[n]+values[n-1])/2
  284.                     except:
  285.                         try: data['median-%s' % name]=(
  286.                             "between %s and %s" % (values[n],values[n-1]))
  287.                         except: pass
  288.  
  289.         return data[key]
  290.  
  291.     def next_batches(self, suffix='batches',key=''):
  292.         if suffix != 'batches': raise KeyError, key
  293.         data=self.data
  294.         sequence=self.items
  295.         try:
  296.             if not data['next-sequence']: return ()
  297.             sz=data['sequence-step-size']
  298.             start=data['sequence-step-start']
  299.             end=data['sequence-step-end']
  300.             l=len(sequence)
  301.             orphan=data['sequence-step-orphan']
  302.             overlap=data['sequence-step-overlap']
  303.         except: AttributeError, 'next-batches'
  304.         r=[]
  305.         while end < l:
  306.             start,end,spam=opt(end+1-overlap,0,sz,orphan,sequence)
  307.             v=sequence_variables(self.items,
  308.                                  self.query_string,self.start_name_re)
  309.             d=v.data
  310.             d['batch-start-index']=start-1
  311.             d['batch-end-index']=end-1
  312.             d['batch-size']=end+1-start
  313.             d['mapping']=data['mapping']
  314.             r.append(v)
  315.         data['next-batches']=r
  316.         return r
  317.  
  318.     def previous_batches(self, suffix='batches',key=''):
  319.         if suffix != 'batches': raise KeyError, key
  320.         data=self.data
  321.         sequence=self.items
  322.         try:
  323.             if not data['previous-sequence']: return ()
  324.             sz=data['sequence-step-size']
  325.             start=data['sequence-step-start']
  326.             end=data['sequence-step-end']
  327.             l=len(sequence)
  328.             orphan=data['sequence-step-orphan']
  329.             overlap=data['sequence-step-overlap']
  330.         except: AttributeError, 'previous-batches'
  331.         r=[]
  332.         while start > 1:
  333.             start,end,spam=opt(0,start-1+overlap,sz,orphan,sequence)
  334.             v=sequence_variables(self.items,
  335.                                  self.query_string,self.start_name_re)
  336.             d=v.data
  337.             d['batch-start-index']=start-1
  338.             d['batch-end-index']=end-1
  339.             d['batch-size']=end+1-start
  340.             d['mapping']=data['mapping']
  341.             r.append(v)
  342.         r.reverse()
  343.         data['previous-batches']=r
  344.         return r
  345.  
  346.  
  347.     special_prefixes={
  348.         'first': first,
  349.         'last': last,
  350.         'previous': previous_batches,
  351.         'next': next_batches,
  352.         # These two are for backward compatability with a missfeature:
  353.         'sequence-index': lambda self, suffix, key: self['sequence-'+suffix],
  354.         'sequence-index-is': lambda self, suffix, key: self['sequence-'+suffix],
  355.         }
  356.     for n in statistic_names: special_prefixes[n]=statistics
  357.  
  358.     def __getitem__(self,key,
  359.                     special_prefixes=special_prefixes,
  360.                     special_prefix=special_prefixes.has_key
  361.                     ):
  362.         data=self.data
  363.         if data.has_key(key): return data[key]
  364.  
  365.         l=rfind(key,'-')
  366.         if l < 0: raise KeyError, key
  367.  
  368.         suffix=key[l+1:]
  369.         prefix=key[:l]
  370.  
  371.         if hasattr(self, suffix):
  372.             try: v=data[prefix+'-index']
  373.             except: pass
  374.             else: return getattr(self,suffix)(v)
  375.  
  376.         if special_prefix(prefix):
  377.             return special_prefixes[prefix](self, suffix, key)
  378.  
  379.         if prefix[-4:]=='-var':
  380.             prefix=prefix[:-4]
  381.             try: return self.value(data[prefix+'-index'],suffix)
  382.             except: pass
  383.  
  384.         if key=='sequence-query': return self.query()
  385.             
  386.         raise KeyError, key
  387.  
  388.  
  389. def sub(s1, s2, src):
  390.     return join(split(src, s1), s2)
  391.  
  392. def opt(start,end,size,orphan,sequence):
  393.     if size < 1:
  394.         if start > 0 and end > 0 and end >= start:
  395.             size=end+1-start
  396.         else: size=7
  397.  
  398.     if start > 0:
  399.  
  400.         try: sequence[start-1]
  401.         except: start=len(sequence)
  402.         # if start > l: start=l
  403.  
  404.         if end > 0:
  405.             if end < start: end=start
  406.         else:
  407.             end=start+size-1
  408.             try: sequence[end+orphan-1]
  409.             except: end=len(sequence)
  410.             # if l - end < orphan: end=l
  411.     elif end > 0:
  412.         try: sequence[end-1]
  413.         except: end=len(sequence)
  414.         # if end > l: end=l
  415.         start=end+1-size
  416.         if start - 1 < orphan: start=1
  417.     else:
  418.         start=1
  419.         end=start+size-1
  420.         try: sequence[end+orphan-1]
  421.         except: end=len(sequence)
  422.         # if l - end < orphan: end=l
  423.     return start,end,size
  424.